package com.kadron.dao;

import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.jboss.seam.Component;

import com.kadron.base.KBase;
import com.kadron.base.KVBase;
import com.kadron.common.KUtil;
import com.kadron.datamodel.KModel;
import com.kadron.exceptions.KPersistenceException;
import com.kadron.exceptions.KVersionException;

public abstract class KDAO<E extends KModel> {

	public Log log = LogFactory.getLog(KDAO.class);
		
	public EntityManager getEntityManager() {
		return (EntityManager) Component.getInstance("entityManager");
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public <T extends KBase> T find(long id, Class clazz) {
		EntityManager em = getEntityManager();
		try {
			return (T) em.createQuery("FROM "+clazz.getName()+" WHERE id = :id")
				.setParameter("id", id)
				.getSingleResult();			
		} catch (NoResultException e) {
			return null;
		}
	}
	
	@SuppressWarnings("rawtypes")
	public boolean exists(long id, Class clazz) {
		EntityManager em = getEntityManager();
		try {
			Object one = em.createQuery("SELECT 1 FROM "+clazz.getName()+" WHERE id = :id")
			.setParameter("id", id)
			.getSingleResult();
			return one!=null;			
		} catch (NoResultException e) {
			return false;
		}
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public <T extends KBase> List<T> getAll(Class clazz) {
		EntityManager em = getEntityManager();
		return em.createQuery("FROM "+clazz.getName()).getResultList();
	}
	
	@SuppressWarnings("unchecked")
	public List<Long> getIDs(Class clazz) {
		EntityManager em = getEntityManager();
		return em.createQuery("SELECT id FROM "+clazz.getName()).getResultList();
	}
	
	public void delete(KBase base) {
		if (base == null) {
			log.error("Call indsert with null.");
			return;
		}
		EntityManager em = getEntityManager();
		base = (KBase) em.merge(base);
		em.remove(base);
	}
	
	public void insert(KBase base) {
		if (base == null) {
			log.error("Call indsert with null.");
			return;
		}
		base.setCreated(KUtil.getMoment());			
		getEntityManager().persist(base);
	}
	
	public KBase update(KBase base) throws KPersistenceException {
		if (base == null) {
			log.error("Call update with null.");
			return null;
		}
		Date moment = KUtil.getMoment();
		if (base.getCreated() == null) {
			base.setCreated(moment);
		} else {
			base.setModified(moment);			
		}
		try {
			base = (KBase) getEntityManager().merge(base);			
		} catch (PersistenceException e) {
			throw new KPersistenceException(e);
		}
		return base;
	}
	
	public KVBase updateVersioned(KVBase base) throws KVersionException {
		if (base == null) {
			log.error("Call update with null.");
			return null;
		}
		Date now = KUtil.getMoment();
		if (base.getCreated() == null) {
			base.setCreated(now);
		} else {
			base.setModified(now);			
		}
		try {
			base = (KVBase) getEntityManager().merge(base);			
		} catch (PersistenceException e) {
			throw new KVersionException(e);
		}
		return base;
	}
	
	@SuppressWarnings("rawtypes")
	public Integer delete(long baseId, Class clazz) {
		EntityManager em = getEntityManager();
		Integer exec = null;
		try {
			 exec = em.createQuery("DELETE FROM "+clazz.getName()+" WHERE id = :id")
			.setParameter("id", baseId)
			.executeUpdate();			
		} catch (HibernateException e) {
			if (log.isErrorEnabled()) {
				log.error("HibernateException on delete, "+e);
			}
		}
		return exec;
	}
	
}
